`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/04/13 16:01:31
// Design Name: 
// Module Name: I2cMaster_ByteCtr
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`include "i2c_master_define.v"

module I2cMaster_ByteCtr(
   input                                   sys_clk,     //system clock 
   input                                   sys_rst_n,   //asynchronous active low reset 
   input                                   sys_rst,     //synchronous active high reset  
   input                                   core_en,     // core enable signal

   input [15:0]                            clk_cnt,     // 4x SCL
   
   // control inputs
   input                                    start,
   input                                    stop,
   input                                    read,
   input                                    write,
   input                                    ack_in,
   output                                   core_ack,
   
   // status outputs
   input [7:0]                              din,
   output [7:0]                             dout,
   output reg                               cmd_ack,    //byte state finsish command complete acknowledge
   output reg                               ack_out,
   output                                   i2c_busy,
   output                                   i2c_al,
   	// I2C signals
   input                                    scl_i,
   output                                   scl_o,
   output                                   scl_oen,
   input                                    sda_i,
   output                                   sda_o,
   output                                   sda_oen   
    );

//signals for bit_controller
reg [3:0]  core_cmd;                      
reg        core_txd;                    
wire       core_ack, core_rxd;          

//********************generate signals for byte control state machine ************************************//    
// generate go-signal
wire       go;
assign go = (read | write | stop) & ~cmd_ack;  

// signals for shift register
reg [7:0] sr; //8bit shift register
reg       shift, ld;
   
// assign dout output to shift-register
assign dout = sr;
     
// generate shift register
always @(posedge sys_clk or negedge sys_rst_n)
    if (!sys_rst_n)
        sr <= #1 8'h0;
    else if (sys_rst)
        sr <= #1 8'h0;
    else if (ld)
        sr <= #1 din;
    else if (shift) 
        sr <= #1 {sr[6:0], core_rxd};
        
// generate counter      
reg  [2:0] dcnt;       // signals for state machine
wire       cnt_done;     

always @(posedge sys_clk or negedge sys_rst_n)
    if (!sys_rst_n)
        dcnt <= #1 3'h0;
    else if (sys_rst)
        dcnt <= #1 3'h0;
    else if (ld)
        dcnt <= #1 3'h7;
    else if (shift)
        dcnt <= #1 dcnt - 3'h1;
     
assign cnt_done = ~(|dcnt);

    
//************************************hookup bit_controller***************************************//
I2cMaster_BitCtr    bit_controller (
    .sys_clk            ( sys_clk       ),
    .sys_rst            ( sys_rst       ),
    .sys_rst_n          ( sys_rst_n     ),
    .core_en            ( core_en       ),
    .clk_cnt            ( clk_cnt       ),
    .cmd                ( core_cmd      ),
    .cmd_ack            ( core_ack      ),
    .busy               ( i2c_busy      ),
    .al                 ( i2c_al        ),
    .din                ( core_txd      ),
    .dout               ( core_rxd      ),
    .scl_i              ( scl_i         ),
    .scl_o              ( scl_o         ),
    .scl_oen            ( scl_oen       ),
    .sda_i              ( sda_i         ),
    .sda_o              ( sda_o         ),
    .sda_oen            ( sda_oen       )
    );    
    
    
    
//********************************generate statemachine****************************************//
// state machine
parameter [4:0] ST_IDLE  = 5'b0_0000;
parameter [4:0] ST_START = 5'b0_0001;
parameter [4:0] ST_READ  = 5'b0_0010;
parameter [4:0] ST_WRITE = 5'b0_0100;
parameter [4:0] ST_ACK   = 5'b0_1000;
parameter [4:0] ST_STOP  = 5'b1_0000;

reg [4:0] c_state;                      // synopsys enum_state	

always @(posedge sys_clk or negedge sys_rst_n)
    if (!sys_rst_n)
        begin
            core_cmd <= #1 `I2C_CMD_NOP;
            core_txd <= #1 1'b0;
            shift    <= #1 1'b0;
            ld       <= #1 1'b0;
            cmd_ack  <= #1 1'b0;
            c_state  <= #1 ST_IDLE;
            ack_out  <= #1 1'b1;  //jt modify from 0 to 1
        end
    else if (sys_rst | i2c_al)
        begin
            core_cmd <= #1 `I2C_CMD_NOP;
            core_txd <= #1 1'b0;
            shift    <= #1 1'b0;
            ld       <= #1 1'b0;
            cmd_ack  <= #1 1'b0;
            c_state  <= #1 ST_IDLE;
            ack_out  <= #1 1'b1;  //jt modify from 0 to 1
        end
    else
        begin
        // initially reset all signals
        core_txd <= #1 sr[7];
        shift    <= #1 1'b0;
        ld       <= #1 1'b0;
        cmd_ack  <= #1 1'b0;
        case (c_state) // synopsys full_case parallel_case
            ST_IDLE:
                if (go)
                    begin
                        if (start)
                            begin
                                c_state  <= #1 ST_START;
                                core_cmd <= #1 `I2C_CMD_START;
                            end
                        else if (read)
                            begin
                                c_state  <= #1 ST_READ;
                                core_cmd <= #1 `I2C_CMD_READ;
                            end
                        else if (write)
                            begin
                                c_state  <= #1 ST_WRITE;
                                core_cmd <= #1 `I2C_CMD_WRITE;
                            end
                        else // stop
                            begin
                                c_state  <= #1 ST_STOP;
                                core_cmd <= #1 `I2C_CMD_STOP;
                            end     
                        ld <= #1 1'b1;                        
                    end
                  else 
                    ack_out  <= #1 1'b1;  //jt add 
     
            ST_START:
                if (core_ack)
                    begin
                        if (read)
                            begin
                                c_state  <= #1 ST_READ;
                                core_cmd <= #1 `I2C_CMD_READ;
                            end
                        else
                            begin
                                c_state  <= #1 ST_WRITE;
                                core_cmd <= #1 `I2C_CMD_WRITE;
                            end     
                        ld <= #1 1'b1;
                    end
     
             ST_WRITE:
                if (core_ack)
                    if (cnt_done)
                        begin
                            c_state  <= #1 ST_ACK;
                            core_cmd <= #1 `I2C_CMD_READ;
                        end
                    else
                        begin
                            c_state  <= #1 ST_WRITE;       // stay in same state
                            core_cmd <= #1 `I2C_CMD_WRITE; // write next bit
                            shift    <= #1 1'b1;
                        end
     
              ST_READ:
                if (core_ack)
                    begin
                        if (cnt_done)
                            begin
                                c_state  <= #1 ST_ACK;
                                core_cmd <= #1 `I2C_CMD_WRITE;
                            end
                        else
                            begin
                                c_state  <= #1 ST_READ;       // stay in same state
                                core_cmd <= #1 `I2C_CMD_READ; // read next bit
                            end     
                        shift    <= #1 1'b1;
                        core_txd <= #1 ack_in;
                    end
     
                ST_ACK:
                  if (core_ack)
                    begin
                        if (stop)
                            begin
                                c_state  <= #1 ST_STOP;
                                core_cmd <= #1 `I2C_CMD_STOP;
                            end
                       else
                            begin
                                c_state  <= #1 ST_IDLE;
                                core_cmd <= #1 `I2C_CMD_NOP;     
                             // generate command acknowledge signal
                             cmd_ack  <= #1 1'b1;
                            end     
                         // assign ack_out output to bit_controller_rxd (contains last received bit)
                         ack_out <= #1 core_rxd;     
                         core_txd <= #1 1'b1;
                     end
                   else
                     core_txd <= #1 ack_in;
     
                ST_STOP:
                  if (core_ack)
                    begin
                        c_state  <= #1 ST_IDLE;
                        core_cmd <= #1 `I2C_CMD_NOP;     
                        // generate command acknowledge signal
                        cmd_ack  <= #1 1'b1;
                    end     
              endcase
          end    
    
   
endmodule
